﻿/*
 * Jonathan
 * Created by: Jonathan Montiverdi
 * Date: 7/13/2012
 * License: http://jonathan.codeplex.com/license
 * 
 * Some of the Regexes were copied from: Toni Lähdekorpi <toni@lygon.net>
 *    https://github.com/lahdekorpi/Wiky.php/blob/master/wiky.inc.php
 */
using System;
using System.Text.RegularExpressions;

namespace Jonathan.DataAccess.MediaWiki
{
   /// <summary>
   /// Description of WikiParser.
   /// </summary>
   public class WikiParser
   {
      public readonly Regex RegEx_Author = new Regex (@"(\[+Author::)([\w\s]+)+(\|)?([\w\s]+)?(\]+)");
      public readonly Regex RegEx_Property = new Regex (@"(\[\[\w+::)([\w\s]+)(\|)?([\w\s]+)?(\]\])");
      public readonly Regex RegEx_WikipediaLink = new Regex (@"(\[\[)(wikipedia:)([\s\w#'’:]+)(\|)?([\s\w#'’:]+)?(]])");
      public readonly Regex RegEx_WikiLink = new Regex (@"\[\[(.+?)\]\]");//(@"(\[\[)([\s\w#'’:]+)(\|)?([\s\w'-:]+)?(\]\])");
      public readonly Regex RegEx_ExLink = new Regex (@"\[((ht|f)tp(s?):\/\/(.+?))(\s(.+))?\]");
      public readonly Regex RegEx_BoldItalic = new Regex (@"\'\'\'\'\'(.+?)\'\'\'\'\'");
      public readonly Regex RegEx_Bold = new Regex (@"\'\'\'(.+?)\'\'\'");
      public readonly Regex RegEx_Italic = new Regex (@"\'\'(.+?)\'\'");
      public readonly Regex RegEx_ListItem = new Regex (@"(\*+)(\s*)(.+)");
      public readonly Regex RegEx_Heading3 = new Regex (@"==== (.+?) ====");
      public readonly Regex RegEx_Heading2 = new Regex (@"=== (.+?) ===");
      public readonly Regex RegEx_Heading1 = new Regex (@"== (.+?) ==");
      public readonly Regex RegEx_Anchor = new Regex (@"\[\[(#\w+)\|?([\w()]+)?\]\]");
      
      // Lists...
      public readonly Regex RegEx_OlList1 = new Regex (@"[\n\r]#.+([\n|\r]#.+)+");
      public readonly Regex RegEx_OlList2 = new Regex (@"[\n\r]#(?!#) *(.+)(([\n\r]#{2,}.+)+)");
      public readonly Regex RegEx_OlList3 = new Regex (@"[\n\r]#{2}(?!#) *(.+)(([\n\r]#{3,}.+)+)");
      public readonly Regex RegEx_OlList4 = new Regex (@"[\n\r]#{3}(?!#) *(.+)(([\n\r]#{4,}.+)+)");

      public readonly Regex RegEx_UlList1 = new Regex (@"[\n\r]\*.+([\n|\r]\*.+)+");
      public readonly Regex RegEx_UlList2 = new Regex (@"[\n\r]\*(?!\*) *(.+)(([\n\r]\*{2,}.+)+)");
      public readonly Regex RegEx_UlList3 = new Regex (@"[\n\r]\*{2}(?!\*) *(.+)(([\n\r]\*{3,}.+)+)");
      public readonly Regex RegEx_UlList4 = new Regex (@"[\n\r]\*{3}(?!\*) *(.+)(([\n\r]\*{4,}.+)+)");

      public readonly Regex RegEx_ListItems = new Regex (@"^[#\*]+ *(.+)$", RegexOptions.Multiline);
      public readonly Regex RegEx_Hr = new Regex (@"----");
      
      /// <summary>
      /// Removes the wiki formatting of the given text.
      /// </summary>
      /// <param name="text">Text to remove wiki formatting from.</param>
      /// <returns>Html text</returns>
      public string UnWiki (string text)
      {
         text = this.RegEx_Property.Replace (text, delegate (Match match)
            {
               return string.Format ("{0}", match.Groups[4].Success ? match.Groups[4].Value : match.Groups[2].Value);
            });
         
         text = this.RegEx_WikipediaLink.Replace (text, delegate (Match match)
            {
               var link = match.Groups[3].Value;
               return string.Format ("<a href=\"http://en.wikipedia.org/wiki/{0}\" title=\"http://en.wikipedia.org/wiki/{0}\">{1}</a>", link,
                                     match.Groups[5].Success ? match.Groups[5].Value : link);
            });
         
         text = this.RegEx_WikiLink.Replace (text, delegate (Match match)
            {
               var link = match.Groups[1].Value.Trim ();
               if (link.Contains ("Category"))
                  return string.Empty;
               
               var innerText = link;
               if (link.Contains ("|"))
               {
                  var linkSplit = link.Split ('|');
                  link = linkSplit [0];
                  innerText = linkSplit [1];
               }
               link = Char.ToUpper (link [0]) + link.Substring (1);
               return string.Format ("<a href=\"{0}\" title=\"{0}\">{1}</a>", link, innerText);
            });
         
         text = this.RegEx_ExLink.Replace (text, delegate (Match match)
            {
               var link = match.Groups[1].Value;
               return string.Format ("<a href=\"{0}\" title=\"{0}\">{1}</a>", link,
                                     match.Groups[6].Success ? match.Groups[6].Value : link);
            });
         
         text = this.RegEx_Anchor.Replace (text, delegate (Match match)
            {
               var link = match.Groups[1].Value;
               return string.Format ("<a href=\"{0}\" title=\"See {1}\">{1}</a>", link,
                                     match.Groups[2].Success ? match.Groups[2].Value : link);
            });
         
         text = this.RegEx_Heading3.Replace (text, delegate (Match match)
            { return string.Format ("<h3>{0}</h3>", match.Groups [1].Value); });
         
         text = this.RegEx_Heading2.Replace (text, delegate (Match match)
            { return string.Format ("<h2>{0}</h2>", match.Groups [1].Value); });
         
         text = this.RegEx_Heading1.Replace (text, delegate (Match match)
            { return string.Format ("<h1>{0}</h1>", match.Groups [1].Value); });
         
         text = this.RegEx_BoldItalic.Replace (text, delegate (Match match)
            { return string.Format ("<strong><em>{0}</em></strong>", match.Groups [1].Value); });
         
         text = this.RegEx_Bold.Replace (text, delegate (Match match)
            { return string.Format ("<strong>{0}</strong>", match.Groups [1].Value); });
         
         text = this.RegEx_Italic.Replace (text, delegate (Match match)
            { return string.Format ("<em>{0}</em>", match.Groups [1].Value); });
         
         text = this.RegEx_OlList1.Replace (text, delegate (Match match)
            { return string.Format ("<ol>{1}{0}{1}</ol>", match.Groups [0].Value, Environment.NewLine); });
         
         text = this.RegEx_OlList2.Replace (text, delegate (Match match)
            {
               return string.Format ("<li>{0}{2}<ol>{1}{2}</ol>{2}</li>", match.Groups [1].Value,
                                     match.Groups [2].Value,
                                     Environment.NewLine);
            });
         
         text = this.RegEx_OlList3.Replace (text, delegate (Match match)
            {
               return string.Format ("<li>{0}{2}<ol>{1}{2}</ol>{2}</li>", match.Groups [1].Value,
                                     match.Groups [2].Value,
                                     Environment.NewLine);
            });
         
         text = this.RegEx_OlList4.Replace (text, delegate (Match match)
            {
               return string.Format ("<li>{0}{2}<ol>{1}{2}</ol>{2}</li>", match.Groups [1].Value,
                                     match.Groups [2].Value,
                                     Environment.NewLine);
            });
         
         text = this.RegEx_UlList1.Replace (text, delegate (Match match)
            { return string.Format ("<ul>{1}{0}{1}</ul>", match.Groups [0].Value, Environment.NewLine); });
         
         text = this.RegEx_UlList2.Replace (text, delegate (Match match)
            {
               return string.Format ("<li>{0}{2}<ul>{1}{2}</ul>{2}</li>", match.Groups [1].Value,
                                     match.Groups [2].Value,
                                     Environment.NewLine);
            });
         
         text = this.RegEx_UlList3.Replace (text, delegate (Match match)
            {
               return string.Format ("<li>{0}{2}<ul>{1}{2}</ul>{2}</li>", match.Groups [1].Value,
                                     match.Groups [2].Value,
                                     Environment.NewLine);
            });
         
         text = this.RegEx_UlList4.Replace (text, delegate (Match match)
            {
               return string.Format ("<li>{0}{2}<ul>{1}{2}</ul>{2}</li>", match.Groups [1].Value,
                                     match.Groups [2].Value,
                                     Environment.NewLine);
            });
         
         text = this.RegEx_ListItems.Replace (text, delegate (Match match)
            { return string.Format ("<li>{0}</li>", match.Groups [1].Value); });
         
         text = this.RegEx_Hr.Replace (text, "<hr />");
         
         return text;
      }
   }
}
